package utils

import (
	"strconv"
	"time"
)

// go 时间格式化使用固定值 "2006-01-02 15:04:05.999999999 -0700 MST"

const (
	GBTimeValFormatYMD = "20060102"
	GBTimeValFormatYMDSep = "2006-01-02"
)

var (
	// 中国本地时区变量
	GBTimeValLocalChina      *time.Location
)

func init() {
	GBTimeValLocalChina, _ = time.LoadLocation("Asia/Shanghai")
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 根据日期取得时间实例，中国本地时区的
func GBTimeLocalDate(year int, month time.Month, day, hour, min, sec, nsec int) time.Time {
	return time.Date(year, month, day, hour, min, sec, nsec, GBTimeValLocalChina)
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 取得当前系统 unix 纳秒
func GBTimeNowUnixNS() int64 {
	return time.Now().UnixNano() / int64(time.Nanosecond)
}

// 取得当前系统 unix 微秒
func GBTimeNowUnixUS() int64 {
	return time.Now().UnixNano() / int64(time.Microsecond)
}

// 取得当前系统 unix 毫秒
func GBTimeNowUnixMS() int64 {
	return time.Now().UnixNano() / int64(time.Millisecond)
}

// 取得当前系统 unix 秒
func GBTimeNowUnixS() int64 {
	return time.Now().UnixNano() / int64(time.Second)
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 传入一个时间，取得这个时间那天的起始时间，即零点的时间
func GBTimeGetStart0OfTimeDay(t time.Time) time.Time {
	//这个解析要添加时区，否则取出来时间戳有时差比如8小时
	result, _ := time.ParseInLocation("2006-01-02", t.Format("2006-01-02"), GBTimeValLocalChina)
	//忽略错误返回结果
	return result
}

//从"起始时间(包含)"到"结束时间(不含)"循环范围内的每一[天]，本地时区
func GBTimeForRangeEachDay(timeBeg, timeEnd time.Time, fcb func(time.Time)) {
	//取整成0点
	timeBeg = GBTimeGetStart0OfTimeDay(timeBeg)
	timeEnd = GBTimeGetStart0OfTimeDay(timeEnd)
	//循环处理
	for {
		//小于结束时间就循环，大于等于结束就中断
		if timeBeg.Unix() < timeEnd.Unix() {
			fcb(timeBeg)
		} else {
			break
		}
		//累加一天
		timeBeg = timeBeg.AddDate(0, 0, 1)
	}
}

// 格式化时间，变成易读的，使用内置的默认格式，只具体到毫秒
func GBTimeFormatReadable(t time.Time) string {
	return t.Format("2006-01-02 15:04:05.999")
}

// 取得当前天，并格式化
func GBTimeGetTodayFormat(fmt string) string {
	return time.Now().Format(fmt)
}

// 取得当前天，格式化并转换为整数
func GBTimeGetTodayFormatYMDAsInt64() int64 {
	result, _ := strconv.ParseInt(time.Now().Format(GBTimeValFormatYMD), 10, 64)
	return result
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 取得当前天以及向前N天的时间
func GBTimeGetTodayAndBeforeDays(dayCount int) [] time.Time {
	result := make([] time.Time, 0, dayCount)
	target := time.Now()
	for i := 0; i < dayCount; i ++ {
		result = append(result, target)
		target = target.AddDate(0, 0, -1)
	}
	return result
}

// 取得当前天以及向前N天的时间，并格式化
func GBTimeGetTodayAndBeforeDaysFormat(dayCount int, fmt string) [] string {
	result := make([] string, 0, dayCount)
	target := time.Now()
	for i := 0; i < dayCount; i ++ {
		result = append(result, target.Format(fmt))
		target = target.AddDate(0, 0, -1)
	}
	return result
}

// 取得当前天以及向后N天的时间
func GBTimeGetTodayAndAfterDays(dayCount int) [] time.Time {
	result := make([] time.Time, 0, dayCount)
	target := time.Now()
	for i := 0; i < dayCount; i ++ {
		result = append(result, target)
		target = target.AddDate(0, 0, 1)
	}
	return result
}

// 取得当前天以及向后N天的时间，并格式化
func GBTimeGetTodayAndAfterDaysFormat(dayCount int, fmt string) [] string {
	result := make([] string, 0, dayCount)
	target := time.Now()
	for i := 0; i < dayCount; i ++ {
		result = append(result, target.Format(fmt))
		target = target.AddDate(0, 0, 1)
	}
	return result
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 通过格式化取得时间
func GBTimeParseFromFormatStringLocation(timestr string, fmt string, local * time.Location) time.Time {
	// 转格式
	timeTarget, err := time.ParseInLocation(fmt, timestr, local)
	// 错误
	if err != nil {
		return time.Unix(0, 0)
	}
	// 成功
	return timeTarget
}

// 通过格式化取得时间，本地时区
func GBTimeParseFromFormatString(timestr string, fmt string) time.Time {
	// 错误
	if nil == GBTimeValLocalChina {
		return GBTimeParseFromFormatStringLocation(timestr, fmt, time.Local)
	}
	// 转换
	return GBTimeParseFromFormatStringLocation(timestr, fmt, GBTimeValLocalChina)
}
